<template>
  <div class="three-sphere-container">
    <div id="container"></div>
    <!-- <div style="position: fixed; left: 0; top: 0" @click="reInit">初始动画</div> -->
  </div>
</template>
<script>
import * as THREE from "three";
// import * as TWEEN from "tween.js";

import TWEEN from "tween.js";
// import THREE from "three";
import {
  CSS3DObject,
  CSS3DRenderer,
} from "three/examples/jsm/renderers/CSS3DRenderer.js";
import { TrackballControls } from "three/examples/jsm/controls/TrackballControls.js";
export default {
  name: "ThreeSphere",
  components: {},
  props: {
    maxNumber: {
      type: Number,
      default: 200,
    },
    winnerList: {
      type: Array,
      default: () => [],
    },
  },
  data() {
    return {
      threeStop: false,
      table: [],
      camera: null,
      scene: null,
      renderer: null,
      controls: null,
      objects: [],
      targets: { table: [], sphere: [], helix: [], grid: [] },
    };
  },
  watch: {
    winnerList: {
      handler(list) {
        if (!list || !list.length) return;
        list.map((item) => {
          const ele = document.getElementById("element" + item);
          if (ele) {
            ele.style.backgroundColor = "rgba(255,255,0," + "0.4)";
          }
        });
      },
      deep: true,
    },
  },
  created() {},
  mounted() {
    this.init();
  },
  methods: {
    // 初始化
    init() {
      for (var i = 0; i < this.maxNumber; i++) {
        this.table.push({
          name: i + 1,
          p_x: (i % 20) + 1,
          p_y: parseInt(i / 20) + 1,
          image: "",
        });
      }
      this.camera = new THREE.PerspectiveCamera(
        35,
        window.innerWidth / window.innerHeight,
        1,
        10000
      );
      this.camera.position.z = 3000;

      this.scene = new THREE.Scene();
      // table
      for (var i = 0; i < this.table.length; i++) {
        this.pushCard(this.table[i]);
      }

      this.initCard(this.objects);

      //渲染
      this.renderer = new CSS3DRenderer();
      this.renderer.setSize(window.innerWidth, window.innerHeight);
      document
        .getElementById("container")
        .appendChild(this.renderer.domElement);

      //鼠标控制
      this.controls = new TrackballControls(
        this.camera,
        this.renderer.domElement
      );
      this.controls.rotateSpeed = 0.5;
      this.controls.minDistance = 500;
      this.controls.maxDistance = 6000;
      this.controls.addEventListener("change", this.render);

      this.changeView();

      window.addEventListener("resize", this.onWindowResize, false);

      this.animate();
    },
    // 创建卡片
    pushCard(info) {
      var element = document.createElement("div");
      element.className = "element";
      element.id = "element" + info.name;
      // element.style.backgroundColor = 'rgba(0,127,127,' + (Math.random() * 0.5 + 0.25) + ')';
      element.style.backgroundColor = "rgba(0,0,0," + "0.3)";

      var symbol = document.createElement("div");
      symbol.className = "symbol";
      element.appendChild(symbol);

      var details = document.createElement("div");
      details.className = "details";
      details.innerHTML = info.name;

      element.appendChild(details);

      var object = new CSS3DObject(element);

      object.position.x = Math.random() * 4000 - 2000;
      object.position.y = Math.random() * 4000 - 2000;
      object.position.z = Math.random() * 4000 - 2000;

      this.scene.add(object);

      this.objects.push(object);

      //表格坐标进行排序
      var object = new THREE.Object3D();
      object.position.x = info.p_x * 140 - 1330;
      object.position.y = -(info.p_y * 180) + 990;

      this.targets.table.push(object);
      return this.objects;
    },
    /**
     * 卡片初始化
     */
    initCard(objects) {
      this.targets.sphere = [];
      // sphere
      let vector = new THREE.Vector3();
      for (let i = 0, l = objects.length; i < l; i++) {
        let phi = Math.acos(-1 + (2 * i) / l);
        let theta = Math.sqrt(l * Math.PI) * phi;

        let object = new THREE.Object3D();

        object.position.setFromSphericalCoords(800, phi, theta);

        vector.copy(object.position).multiplyScalar(2);

        object.lookAt(vector);

        this.targets.sphere.push(object);
      }
      // helix
      this.targets.helix = [];
      let vector2 = new THREE.Vector3();
      for (let i = 0; i < objects.length; i++) {
        let theta = i * 0.175 + Math.PI;
        let y = -(i * 8) + 450;

        let object = new THREE.Object3D();

        object.position.setFromCylindricalCoords(900, theta, y);

        vector2.x = object.position.x * 2;
        vector2.y = object.position.y;
        vector2.z = object.position.z * 2;

        object.lookAt(vector2);
        this.targets.helix.push(object);
      }
      // grid
      this.targets.grid = [];
      for (let i = 0; i < objects.length; i++) {
        let object = new THREE.Object3D();

        object.position.x = (i % 5) * 400 - 800;
        object.position.y = -(Math.floor(i / 5) % 5) * 400 + 800;
        object.position.z = Math.floor(i / 25) * 1000 - 2000;
        this.targets.grid.push(object);
      }
    },
    transform(targets, duration, field = "rotation") {
      TWEEN.removeAll();

      for (let i = 0; i < this.objects.length; i++) {
        let object = this.objects[i];
        let target = targets[i];

        new TWEEN.Tween(object.position)
          .to(
            {
              x: target.position.x,
              y: target.position.y,
              z: target.position.z,
            },
            Math.random() * duration + duration
          )
          .easing(TWEEN.Easing.Exponential.InOut)
          .start();

        new TWEEN.Tween(object.rotation)
          .to(
            {
              x: target[field].x,
              y: target[field].y,
              z: target[field].z,
            },
            Math.random() * duration + duration
          )
          .easing(TWEEN.Easing.Exponential.InOut)
          .start();
      }

      // return;

      // new TWEEN.Tween(targets)
      //   .to({}, duration * 2)
      //   .onUpdate(this.render())
      //   .start();
    },
    // 渲染
    render() {
      this.renderer.render(this.scene, this.camera);
    },
    // 屏幕尺寸更改
    onWindowResize() {
      this.camera.aspect = window.innerWidth / window.innerHeight;
      this.camera.updateProjectionMatrix();

      this.renderer.setSize(window.innerWidth, window.innerHeight);

      this.render();
    },
    // 动画
    animate() {
      //scene.rotation.x += 0.009;
      if (!this.threeStop) {
        this.scene.rotation.y += 0.002;
        requestAnimationFrame(this.animate);
        TWEEN.update();
        this.controls.update();
      }

      //循环渲染
      this.render();
    },
    // 自动更换
    changeView() {
      var ini = 0;
      const targets = this.targets;
      setInterval(() => {
        ini = ini >= 4 ? 0 : ini;
        ++ini;
        switch (ini) {
          case 1:
            this.transform(targets.sphere, 2000);
            break;
          case 2:
            this.transform(targets.helix, 2000);
            break;
          case 3:
            this.transform(targets.grid, 2000);
            break;
          case 4:
            this.transform(targets.table, 2000);
            break;
        }
      }, 10000);
    },
    // 重置
    reInit() {
      this.transform(this.targets.grid, 2000);
      setTimeout(() => {
        this.transform(this.targets.sphere, 2000);
      }, 5000);
      // this.objects.forEach((item) => {
      //   this.scene.remove(item);
      // });
      // this.objects = [];
      // for (let i = 0; i < 200; i++) {
      //   setTimeout(() => {
      //     this.objects = this.pushCard({
      //       name: i + 1,
      //       p_x: (i % 20) + 1,
      //       p_y: parseInt(i / 20) + 1,
      //       image: "",
      //     });
      //     this.initCard(this.objects);
      //     if (i === 199) this.transform(this.targets.sphere, 100);
      //   }, 0);
      // }
    },
    // 清除模型
    clearScene() {
      // 从scene中删除模型并释放内存
      if (this.objects.length > 0) {
        for (var i = 0; i < this.objects.length; i++) {
          var currObj = this.objects[i];

          // 判断类型
          if (currObj instanceof THREE.Scene) {
            var children = currObj.children;
            for (var i = 0; i < children.length; i++) {
              this.deleteGroup(children[i]);
            }
          } else {
            this.deleteGroup(currObj);
          }
          this.scene.remove(currObj);
        }
      }
    },
    // 删除group，释放内存
    deleteGroup(group) {
      //console.log(group);
      if (!group) return;
      // 删除掉所有的模型组内的mesh
      group.traverse(function (item) {
        if (item instanceof THREE.Mesh) {
          item.geometry.dispose(); // 删除几何体
          item.material.dispose(); // 删除材质
        }
      });
    },
  },
};
</script>
<style lang="scss" scoped>
@import "./three-sphere.css";
</style>
